package com.jinzecloud.reportapproval.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.code.kaptcha.Producer;
import com.jinzecloud.reportapproval.bean.Admin;
import com.jinzecloud.reportapproval.bean.RoleUserEntity;
import com.jinzecloud.reportapproval.dto.Param;
import com.jinzecloud.reportapproval.execption.Code;
import com.jinzecloud.reportapproval.form.RoleUserUpdateForm;
import com.jinzecloud.reportapproval.mapper.AdminMapper;
import com.jinzecloud.reportapproval.service.AdminService;
import com.jinzecloud.reportapproval.service.RoleMenuService;
import com.jinzecloud.reportapproval.service.RoleUserService;
import com.jinzecloud.reportapproval.utils.*;
import com.jinzecloud.reportapproval.vo.*;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service("adminService")
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {

    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private RoleUserService roleUserService;
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private JwtUtil jwtUtil;
    @Autowired
    private Producer producer;
    @Autowired
    RedisUtils redisUtils;
    @Value("${reportapproval.admin.code}")
    String codePrefix;
    @Value("${reportapproval.admin.token}")
    String tokenPrefix;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private FileUploadUtil fileUploadUtil;
    @Autowired
    private HttpServletRequest request;

    @Override
    public PageUtils queryPage(Param param) {
        String pageSize = param.getPage();
        String limit = param.getLimit();
        String key = param.getKey();
        Map<String, Object> params = new HashMap<>();
        params.put("page", pageSize);
        params.put("limit", limit);
        MPJLambdaWrapper<Admin> adminQueryWrapper = new MPJLambdaWrapper<>();
        if (!StringUtils.isEmpty(key)) {
            adminQueryWrapper.eq("ad_id", key).or()
                    .like("ad_user_name", key).or()
                    .like("ad_name", key);
        }
        IPage<AdminListVo> page = adminMapper.selectJoinPage(
                new Page<AdminListVo>(Long.parseLong((String) params.get("page")), Long.parseLong((String) params.get("limit"))),
                AdminListVo.class,
                adminQueryWrapper
        );
        List<AdminListVo> AdminListVo = page.getRecords().stream().map(adminListVo -> {
            QueryWrapper<RoleUserEntity> roleUserEntityQueryWrapper = new QueryWrapper<>();
            roleUserEntityQueryWrapper.eq("user_id", adminListVo.getAdId());
            List<RoleUserEntity> list = roleUserService.list(roleUserEntityQueryWrapper);
            List<Long> roleIds = list.stream().map(RoleUserEntity::getRoleId).collect(Collectors.toList());
            adminListVo.setRoleIds(roleIds);
            return adminListVo;
        }).collect(Collectors.toList());

        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(AdminListVo);
        return pageUtils;
    }

    @Override
    public int getIdByName(String name) {
        return Optional.ofNullable(getOne(new LambdaQueryWrapper<Admin>().eq(Admin::getAdUserName, name)))
                .map(Admin::getAdId).orElse(0);
    }

    @Override
    public void getCode(HttpServletRequest request, HttpServletResponse response, String uuid) throws Exception {
        //生成文字验证码
        String code = producer.createText();
        // 获取图片验证码
        BufferedImage image = producer.createImage(code);
        redisUtils.hset(codePrefix + code, code, uuid, 180);
        // 直接在浏览器页面进行显示
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
//        return R.ok().put("img",ImageIO);
    }

    @Override
    public R login(AdminVo adminVo) {
        Map map = new HashMap();
        String authcode = adminVo.getAuthcode();
        System.out.println(redisUtils.hget(codePrefix + authcode, authcode));
        String code = (String) redisUtils.hget(codePrefix + authcode, authcode);
        if (StringUtils.isEmpty(code)) {
            return R.error(Code.CODEPASTDUE_EXCEPTION.getCode(), Code.CODEPASTDUE_EXCEPTION.getMsg());
        }
        if (!adminVo.getUuid().equals(code)) {
            return R.error(Code.CODE_EXCEPTION.getCode(), Code.CODE_EXCEPTION.getMsg());
        } else {
            try {
                Authentication authentication = new UsernamePasswordAuthenticationToken(adminVo.getAdUserName(), adminVo.getAdPassWord());
                authenticationManager.authenticate(authentication);
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (AuthenticationException e) {
                e.printStackTrace();
                return R.error("账号或密码错误");
            }
            UserDetails userDetails = userDetailsService.loadUserByUsername(adminVo.getAdUserName());
            String token = jwtUtil.generateToken(userDetails);
            Admin user_name = this.getOne(new QueryWrapper<Admin>()
                    .select(Admin.class,
                            info -> !info.getColumn().equals("ad_pass_word")).eq("ad_user_name", adminVo.getAdUserName()));
		    // 前端菜单和功能点清单
            List<RoleVO> roleList = roleUserService.getRoleIdList((long) user_name.getAdId());
            List<MenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), user_name.getAdministratorFlag());
            LoginResultVO loginResultVO = new LoginResultVO();
            loginResultVO.setMenuList(TreeUtil.build(menuAndPointsList, 0L, (menuVO, tree) -> {
                tree.setId(menuVO.getId());
                tree.setName(menuVO.getName());
                tree.setParentId(menuVO.getParentId());
                tree.put("url", menuVO.getUrl());
            }));
            loginResultVO.setToken(token);
            loginResultVO.setUser(user_name);
            loginResultVO.setRoleList(roleList.stream().map(RoleVO::getRoleCode).toList());
            return R.ok().put("data", loginResultVO);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveAdmin(AdminRoleVo adminRoleVo) {
        QueryWrapper<Admin> adminQueryWrapper = new QueryWrapper<>();
        adminQueryWrapper.eq("ad_user_name", adminRoleVo.getAdUserName());
        Admin SelectiveAdmin = this.getOne(adminQueryWrapper);
        if (SelectiveAdmin != null) {
            return R.error(Code.USER_ALREADY_EXISTS.getMsg());
        } else {
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            adminRoleVo.setAdPassWord(bCryptPasswordEncoder.encode(adminRoleVo.getAdPassWord()));
            Admin admin = new Admin();
            BeanUtils.copyProperties(adminRoleVo, admin);
            if (adminRoleVo.isAdStatus()){
                admin.setAdStatus(1 + "");
            }else {
                admin.setAdStatus(0 + "");
            }
            if (adminRoleVo.getRoleIds().contains(9)){
                admin.setAdministratorFlag(0);
            }else {
                admin.setAdministratorFlag(1);
            }
            this.save(admin);
            List<String> roleIds = adminRoleVo.getRoleIds();
            for (String roleId : roleIds) {
                RoleUserEntity roleUserEntity = new RoleUserEntity();
                roleUserEntity.setRoleId(Long.parseLong(roleId));
                roleUserEntity.setUserId(Long.parseLong(String.valueOf(admin.getAdId())));
                roleUserService.saveUserRole(roleUserEntity);
            }
        }
        return R.ok();
    }


    @Override
    public R fileUplod(String adminId, MultipartFile file) throws IOException {
        String s = "";
        if (FileUtil.getSuffix(file.getOriginalFilename()).equals("docx")) {
            s = fileUploadUtil.validateFile(file, "WD");
        } else {
            s = fileUploadUtil.validateFile(file, "TP");
        }

        if (s != null) {
            return R.error(s);
        }
        String suffix = FileUtil.getSuffix(file.getOriginalFilename());
        String fileName = StrUtil.uuid().replaceAll("-", "") + "." + suffix;
        fileUploadUtil.createDirectory("signature");
        String path = fileUploadUtil.getUploadFilePath("signature") + fileName;
        System.out.println(path);
        file.transferTo(FileUtil.file(path));
        return R.ok().put("data", RequestUtils.getBasePath(request) + "upload/signature/" + fileName);
    }

    @Override
    public void updateByIdAdminRoleVo(AdminVos adminRoleVo) {
        QueryWrapper<RoleUserEntity> roleUserEntityQueryWrapper = new QueryWrapper<>();
        roleUserEntityQueryWrapper.eq("user_id", adminRoleVo.getAdId());
        roleUserService.remove(roleUserEntityQueryWrapper);
//        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//        adminRoleVo.setAdPassWord(bCryptPasswordEncoder.encode(adminRoleVo.getAdPassWord()));
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminRoleVo, admin);
        if (adminRoleVo.isAdStatus()){
            admin.setAdStatus(1 + "");
        }else {
            admin.setAdStatus(0 + "");
        }
        if (adminRoleVo.getRoleIds().contains(9)){
            admin.setAdministratorFlag(0);
        }else {
            admin.setAdministratorFlag(1);
        }
        this.updateById(admin);
        List<String> roleIds = adminRoleVo.getRoleIds();
        for (String roleId : roleIds) {
            RoleUserEntity roleUserEntity = new RoleUserEntity();
            roleUserEntity.setRoleId(Long.parseLong(roleId));
            roleUserEntity.setUserId(Long.parseLong(String.valueOf(admin.getAdId())));
            roleUserService.saveUserRole(roleUserEntity);
        }
    }

    @Override
    public AdminVos getByIdRoleUser(Integer adId) {
        Admin admin = this.getById(adId);
        AdminVos adminRoleVo = new AdminVos();
        BeanUtils.copyProperties(admin, adminRoleVo);
        if (adminRoleVo.isAdStatus()){
            adminRoleVo.setAdStatus(true);
        }else {
            adminRoleVo.setAdStatus(false);
        }
        QueryWrapper<RoleUserEntity> roleUserEntityQueryWrapper = new QueryWrapper<>();
        roleUserEntityQueryWrapper.eq("user_id", adId);
        List<RoleUserEntity> roleUserEntityList = roleUserService.list(roleUserEntityQueryWrapper);
        adminRoleVo.setRoleIds(roleUserEntityList.stream().map(roleUserEntity -> {
            return roleUserEntity.getRoleId().toString();
        }).collect(Collectors.toList()));
        return adminRoleVo;
    }

    @Override
    public Map<String, Object> Logout(String token) {
        Map map = new HashMap();
        map.put("data","退出成功");
        return map;
    }

    @Override
    public List<Admin> getByIdAndName() {
        QueryWrapper<Admin> adminQueryWrapper = new QueryWrapper<>();
        adminQueryWrapper.select("ad_id","ad_name");
        return this.list(adminQueryWrapper);
    }
}
